#include "ClientSideParser.h"
#include "Configuraciones.h"
#include "Dado.h"
#include <list>
#include "MensajeChat.h"
#include "MensajeDeExcepcion.h"
#include "MensajeDeSolicitud.h"
#include "MensajeDeSolicitudDeTirarDados.h"
#include "MensajeDeFinalizacion.h"
#include "BuzonDeMensajes.h"
#include "MensajeMostrarDados.h"
#include "Jugador.h"
#include "MapaParser.h"
#include <iostream>
#include <cstdlib>

ClientSideParser::ClientSideParser(Cliente* cliente): xmlpp::SaxParser()
{
	this->cliente = cliente;
	this->tipoDeMensaje = "";
	this->parseoFinalizado = false;
	this->mapaParser = NULL;
}

bool ClientSideParser::isParseoFinalizado() {
	return this->parseoFinalizado;
}

ClientSideParser::~ClientSideParser()
{
}

void ClientSideParser::on_start_element(const Glib::ustring& name,
                                   const xmlpp::SaxParser::AttributeList& attributes)
{
	if (name.compare("unirseOk") == 0)
		this->cliente->setUnidoAlJuego();
	else if (name.compare("Textura") == 0) {
		this->cliente->setBajandoImagen();
		getTextura(attributes);
	}
	else if (name.compare("mapaxml") == 0) {
		this->cliente->setBajandoMapa();
	}
	else if (name.compare("configuraciones") == 0) {
		getConfiguracionesDelJuego(attributes);
	}
	else if (name.compare("estado") == 0) {
		updateEstadoDelJuego(attributes);
	}
	else if (name.compare("dados") == 0) {
		generarMensajeMostrarDados(attributes);
	}
	else if (name.compare("turno") == 0) {
		updateTurno(attributes);
	}
	else if (name.compare("territorio") == 0) {
		updateTerritorio(attributes);
	}
	else if (name.compare("datosJugador") == 0) {
		updateDatosJugadores(attributes);
	}
	else if (name.compare("chat") == 0) {
		generarMensajeChat(attributes);
	}
	else if (name.compare("jugador") == 0){
		updateJugador(attributes);
	}
	else if (name.compare("solicitudTirarDados") == 0) {
		generarMensajeDeSolicitudTirarDados(attributes);
	}
	else if (name.compare("excepcion") == 0) {
		generarMensajeDeExcepcion(attributes);
	}
	else if (name.compare("cartaDeObjetivos") == 0) {
		setCartaDeObjetivos(attributes);
	}
	else if (name.compare("finalizacion") == 0) {
		generarMensajeDeFinalizacion(attributes);
	}
}

void ClientSideParser::generarMensajeDeFinalizacion(const xmlpp::SaxParser::AttributeList& attributes) {
	string causa = "";
	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
		if (iter->name.compare("causa") == 0)
			causa = iter->value;
	this->cliente->getBuzonDeMensajesDeFinalizacion()->nuevoMensaje(new MensajeDeFinalizacion(causa));
}

void ClientSideParser::setCartaDeObjetivos(const xmlpp::SaxParser::AttributeList& attributes) {
	int numero = 0;
	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
		if (iter->name.compare("numero") == 0)
			numero = atoi((iter->value).data());
	this->cliente->getJugador()->setCartaDeObjetivos(this->cliente->getMapa()->obtenerCarta(numero));
}

void ClientSideParser::generarMensajeDeSolicitudTirarDados(const xmlpp::SaxParser::AttributeList& attributes) {
	Territorio* territorioJugador;
	Territorio* territorioEnemigo;
	Jugador* jugador;
	int cantidadDeEjercitos;
	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter){
		if (iter->name.compare("jugadorAtacante") == 0)
			jugador = this->cliente->getJuego()->getJugador(iter->value);
		else if (iter->name.compare("territorioAtacante") == 0)
			territorioJugador = this->cliente->getJuego()->getMapa()->obtenerTerritorio(iter->value);
		else if (iter->name.compare("territorioEnemigo") == 0)
				territorioEnemigo = this->cliente->getJuego()->getMapa()->obtenerTerritorio(iter->value);
		else if (iter->name.compare("cantidadDeEjercitos") == 0)
				cantidadDeEjercitos = atoi(iter->value.data());
	}
	Ataque ataque(jugador,territorioJugador,territorioEnemigo,cantidadDeEjercitos);
	MensajeDeSolicitudDeTirarDados *mensaje = new MensajeDeSolicitudDeTirarDados(ataque);
	this->cliente->getBuzonDeMensajesDeSolicitud()->nuevoMensaje(mensaje);
}

void ClientSideParser::generarMensajeDeExcepcion(const xmlpp::SaxParser::AttributeList& attributes) {
	string descripcion = "";
	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
		if (iter->name.compare("descripcion") == 0)
			descripcion = iter->value;
	MensajeDeExcepcion* mensaje = new MensajeDeExcepcion(descripcion);
	this->cliente->getBuzonDeMensajesDeExcepcion()->nuevoMensaje(mensaje);
}

void ClientSideParser :: updateJugador(const xmlpp::SaxParser::AttributeList& attributes){
	string color = "";
	string ejercitos = "";
	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
		if (iter->name.compare("color") == 0)
			color = iter->value;
		else if (iter->name.compare("ejercitos") == 0)
			ejercitos = iter->value;
	int ejer = atoi(ejercitos.data());
	this->cliente->getJuego()->getJugador(color)->setEjercitos(ejer);
}

void ClientSideParser::updateEstadoDelJuego(const xmlpp::SaxParser::AttributeList& attributes) {
	string nombreEstado = "";
	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
		if (iter->name.compare("nombre") == 0)
			this->cliente->getJuego()->setEstado(iter->value);
}

void ClientSideParser::generarMensajeChat(const xmlpp::SaxParser::AttributeList& attributes) {
	string remitente = "";
	string texto = "";
	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
		if (iter->name.compare("remitente") == 0)
			remitente = iter->value;
		else if (iter->name.compare("texto") == 0)
			texto = iter->value;
	MensajeChat* mensaje = new MensajeChat(remitente, texto);
	this->cliente->getBuzonDeMensajesDeChat()->nuevoMensaje(mensaje);
}

void ClientSideParser::parse_chunk(const Glib::ustring& chunk) {
	if (this->cliente->getEstado() == Cliente::DESCARGANDO_MAPA) {
		if (this->mapaParser == NULL)
			this->mapaParser = new MapaParser(this->cliente->getMapa());
		this->mapaParser->parse_chunk(chunk);
		if (this->mapaParser->isParseoFinalizado()) {
			this->cliente->setMapaDescargado();
			delete mapaParser;
		}
	}
	else
		xmlpp::SaxParser::parse_chunk(chunk);
}

void ClientSideParser::getTextura(const xmlpp::SaxParser::AttributeList& attributes) {

	string t_sBase64;

	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) {
	
		if (iter->name.compare("Base64") == 0) {
			t_sBase64 = iter->value.data();
		}
	}
	this->cliente->setTextura(t_sBase64);
}

void ClientSideParser::updateDatosJugadores(const xmlpp::SaxParser::AttributeList& attributes) {
	string colorJugador = "";
	string nombre = "";
	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
		if (iter->name.compare("nombre") == 0)
			nombre = iter->value;
		else if (iter->name.compare("color") == 0)
			colorJugador = iter->value;
	this->cliente->getJuego()->getJugadores()->push_back(new Jugador(nombre,colorJugador));
}

void ClientSideParser::getConfiguracionesDelJuego(const xmlpp::SaxParser::AttributeList& attributes) {
	int cantidadJugadores = 0;
	string mundo = "";
	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
		if (iter->name.compare("jugadores") == 0)
			cantidadJugadores = atoi(iter->value.data());
		else if (iter->name.compare("mundo") == 0)
			mundo = iter->value;
	Configuraciones configuraciones(cantidadJugadores,mundo);	
	this->cliente->setConfiguracionesDelJuego(configuraciones);
}

void ClientSideParser::updateTerritorio(const xmlpp::SaxParser::AttributeList& attributes) {
	string nombre = "";
	string colorJugador = "";
	int cantidadEjercitos = 0;
	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
		if (iter->name.compare("nombre") == 0)
			nombre = iter->value;
		else if (iter->name.compare("ejercitos") == 0)
			cantidadEjercitos = atoi(iter->value.data());
		else if (iter->name.compare("colorJugador") == 0)
			colorJugador = iter->value;
	this->cliente->getJuego()->getMapa()->obtenerTerritorio(nombre)->setEjercitos(cantidadEjercitos, colorJugador);
}

void ClientSideParser::updateTurno(const xmlpp::SaxParser::AttributeList& attributes) {
	string colorJugador = "";
	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
		if (iter->name.compare("colorJugador") == 0)
			colorJugador = iter->value;
	this->cliente->getJuego()->setTurno(colorJugador);
}

void ClientSideParser::generarMensajeMostrarDados(const xmlpp::SaxParser::AttributeList& attributes) {
	list<Dado*> dadosAtacante;
	list<Dado*> dadosDefensor;
	Territorio* atacante;
	Territorio* enemigo;
	for(xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
		if (iter->name.compare("dadoAtacante1") == 0) {
			Dado* dado = new Dado(1);
			dado->setValor(atoi(iter->value.data()));
			dadosAtacante.push_back(dado);
		}
		else if (iter->name.compare("dadoAtacante2") == 0) {
			Dado* dado = new Dado(2);
			dado->setValor(atoi(iter->value.data()));
			dadosAtacante.push_back(dado);
		}
		else if (iter->name.compare("dadoAtacante3") == 0) {
			Dado* dado = new Dado(3);
			dado->setValor(atoi(iter->value.data()));
			dadosAtacante.push_back(dado);
		}
		else if (iter->name.compare("dadoDefensor1") == 0) {
			Dado* dado = new Dado(4);
			dado->setValor(atoi(iter->value.data()));
			dadosDefensor.push_back(dado);
		}
		else if (iter->name.compare("dadoDefensor2") == 0) {
			Dado* dado = new Dado(5);
			dado->setValor(atoi(iter->value.data()));
			dadosDefensor.push_back(dado);
		}
		else if (iter->name.compare("atacante") == 0) {
			atacante = this->cliente->getMapa()->obtenerTerritorio(iter->value);
		}
		else if (iter->name.compare("defensor") == 0)
			enemigo = this->cliente->getMapa()->obtenerTerritorio(iter->value);
	MensajeMostrarDados* mensaje = new MensajeMostrarDados(dadosAtacante,dadosDefensor,atacante,enemigo);
	this->cliente->getBuzonDeMensajesMostrarDados()->nuevoMensaje(mensaje);
}

void ClientSideParser::on_end_element(const Glib::ustring& name)
{
	if ((name.compare("unirseOk") == 0) || (name.compare("MensajeTextura") == 0) || (name.compare("mapaxml") == 0) || 
			(name.compare("updateTurno") == 0) || (name.compare("nombre") == 0) || (name.compare("configuraciones") == 0)||
			(name.compare("updateJugadores") == 0) || (name.compare("chat") == 0) || (name.compare("MensajeMostrarDados") == 0) ||
			(name.compare("updateEstado") == 0) || (name.compare("updateTerritorio") == 0) || (name.compare("updateJugador") == 0))
		this->parseoFinalizado = true;
}

void ClientSideParser::on_characters(const Glib::ustring& text)
{
}

void ClientSideParser::on_comment(const Glib::ustring& text)
{
}

void ClientSideParser::on_warning(const Glib::ustring& text)
{
  std::cout << "on_warning(): " << text << std::endl;
}

void ClientSideParser::on_error(const Glib::ustring& text)
{
	std::cout << "on_error(): " << text << std::endl;
}

void ClientSideParser::on_fatal_error(const Glib::ustring& text)
{
  std::cout << "on_fatal_error(): " << text << std::endl;
}
